package com.xh.easyretry.visitor;


import com.xh.easyretry.common.XHRetryContext;
import com.xh.easyretry.common.XHRetryResult;
import com.xh.easyretry.listener.*;
import com.xh.easyretry.utils.StreamAsyncTask;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

@Slf4j
public class RetryVisitor extends Visitor {

    private static volatile RetryVisitor INSTANCE;
    private List<RetryListener<XHRetryContext>> retryCountListenerList;
    private List<RetryListener<XHRetryResult>> retryResultListenerList;

    private RetryVisitor() {
    }

    public static RetryVisitor getInstance() {
        if (Objects.isNull(INSTANCE)) {
            synchronized (RetryVisitor.class) {
                INSTANCE = new RetryVisitor();
                INSTANCE.registerRetryCountListener();
                INSTANCE.registerRetryResultListener();
            }
        }
        return INSTANCE;
    }


    @Override
    public void visit(XHRetryContext retryContext) {
        if (Objects.isNull(retryContext)) {
            return;
        }
        StreamAsyncTask.of(retryCountListenerList)
                .forEachRunAsync(retryListener -> {
                    try {
                        retryListener.listen(retryContext);
                    } catch (Exception e) {
                        log.error("重试执行回调触发失败");
                    }
                }).collect();
    }

    @Override
    public void visit(XHRetryResult retryResult) {
        if (Objects.isNull(retryResult)) {
            return;
        }
        StreamAsyncTask.of(retryResultListenerList)
                .forEachRunAsync(retryListener -> {
                    try {
                        retryListener.listen(retryResult);
                    } catch (Exception e) {
                        log.error("重试结果回调触发失败");
                    }
                }).collect();
    }

    private void registerRetryCountListener() {
        this.retryCountListenerList = Arrays.asList(
                new FirstRetryListener<>(),
                new LastRetryListener<>()
        );
    }

    private void registerRetryResultListener() {
        this.retryResultListenerList = Arrays.asList(
                new RetryFailedListener<>(),
                new LastFailedListener<>()
        );
    }
}
